package com.teamwin.hdmi;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;

import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.AssetManager;

public class InstallerThread extends Thread implements Runnable {
	private Installer parent;
	
	private int osVersion;
	
	private static final int AOSP = 0;
	private static final int SENSE = 1;
	
	private int installReason;
	
	private SharedPreferences settings = null;
	private SharedPreferences.Editor editor = null;
	
	public InstallerThread(Installer parent, int installReason) {
		this.parent = parent;
		this.installReason = installReason;
	}
	
	public int checkROMType() {
		int rval = 0;
		try {
			File file = new File("/system/build.prop");
			BufferedReader data = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
			String line = data.readLine();
			while(line != null) {
				if(line.contains("ro.modversion=Cyanogen")) {
					rval = AOSP;
					return rval;
				} else if(line.contains("ro.modversion=MIUI")) {
					rval = AOSP;
					return rval;
				} else if(line.contains("ro.modversion=myn")) {
					rval = SENSE;
					return rval;
				} else if(line.contains("ro.build.display.id=Salvage")) {
					rval = AOSP;
					return rval;
				}
				line = data.readLine();
			}
		} catch (Exception e) {
			System.out.println("Failure to parse build.prop: " + e);
		}
		//if it reaches this point, cyanogenmod and miui were not found, probably sense ROM
		rval = SENSE;
		return rval;
	}
	
	public void run() {
		this.settings = this.parent.getSharedPreferences(SocketManager.APP_SETTINGS, 0);
		this.editor = this.settings.edit();
		
		switch (installReason) {
			case SocketManager.NEW_DAEMON:
				this.installNewDaemon();
				break;
			case SocketManager.NEED_KERNEL:
//				installNewKernel();
				break;
			default:
				break;
		}
	}
	
	@SuppressWarnings("static-access")
	public void installNewDaemon() {
		boolean newDaemonWritten = true;
		Process p;
		DataOutputStream dos = null;

		try {
			p = Runtime.getRuntime().exec("su");
			dos = new DataOutputStream(p.getOutputStream());
			
			dos.write("chmod 777 /data/hdmid/\n".getBytes());
			Thread.currentThread().sleep(200);
			dos.flush();
			
			dos.write("rm -rf /data/hdmid/hdmid\n".getBytes());
			Thread.currentThread().sleep(500);
			dos.flush();
			
//			dos.write("chmod 777 /data/hdmid\n".getBytes());
//			Thread.currentThread().sleep(100);
//			dos.flush();
			
			System.out.println("Deleted existing daemon!");
			
			File file = new File("/data/hdmid/");
			if (!file.exists()) {
				dos.write("mkdir /data/hdmid\n".getBytes());
				Thread.currentThread().sleep(300);
				dos.flush();
				dos.write("chmod 777 /data/hdmid/\n".getBytes());
				Thread.currentThread().sleep(200);
				dos.flush();
			}
			
			file = new File("/data/hdmid/banners/");
			if (!file.exists()) {
				dos.write("mkdir /data/hdmid/banners\n".getBytes());
				Thread.currentThread().sleep(300);
				dos.flush();
				dos.write("chmod 777 /data/hdmid/banners/\n".getBytes());
				Thread.currentThread().sleep(200);
				dos.flush();
				
				try {
					String bannerFile = "default.1280x720.0.0.16";
					this.downloadFile(
							"http://techerrata.com/shinzul/banners/" + bannerFile,
							"/data/banners/" + bannerFile);
					bannerFile = "default.1280x720.0.1.16";
					this.downloadFile(
							"http://techerrata.com/shinzul/banners/" + bannerFile,
							"/data/banners/" + bannerFile);
					bannerFile = "default.1280x720.1.0.16";
					this.downloadFile(
							"http://techerrata.com/shinzul/banners/" + bannerFile,
							"/data/banners/" + bannerFile);
					bannerFile = "default.1280x720.1.1.16";
					this.downloadFile(
							"http://techerrata.com/shinzul/banners/" + bannerFile,
							"/data/banners/" + bannerFile);
				} catch (Exception ex) {
					// nothing
				}
			}
			
			newDaemonWritten = this.downloadFile(
					"http://techerrata.com/shinzul/hdmid/hdmid-" + this.parent.getDaemonVersion(),
					"/data/hdmid/hdmid");
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		try {
			if (newDaemonWritten) {
				p = Runtime.getRuntime().exec("su");
				dos = new DataOutputStream(p.getOutputStream());
				
				this.parent.sendCommand(this.parent.DAEMON_QUIT, null);
				
				dos.write("mount -o remount,rw /dev/block/mtdblock4 /system\n".getBytes());
				Thread.currentThread().sleep(1000);
				dos.flush();
				
				dos.write("cat /data/hdmid/hdmid > /system/bin/hdmid\n".getBytes());
				Thread.currentThread().sleep(2000);
				dos.flush();
				
				dos.write("chmod 755 /system/bin/hdmid\n".getBytes());
				Thread.currentThread().sleep(500);
				dos.flush();
				
				dos.write("hdmid &\n".getBytes());
				Thread.currentThread().sleep(500);
				dos.flush();
				
				this.parent.startActivity(new Intent(this.parent, HDMwIn.class));
				this.parent.finish();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public boolean downloadFile(String remoteFileName, String localFileName) {
		boolean rval = true;
		HttpURLConnection urlConnection = null;
		URL url = null;
		OutputStream out = null;
		
		try {
			System.out.println("Downloading " + remoteFileName);
			url = new URL(remoteFileName);
			urlConnection = (HttpURLConnection) url.openConnection();
			InputStream is = urlConnection.getInputStream();
			
			byte buf[] = new byte[1024];
			int len;
			out = new FileOutputStream(new File(localFileName));
		    while((len = is.read(buf)) > 0) {
		    	out.write(buf, 0, len);
		    }
	    
		    System.out.println("new file written at " + localFileName);
		} catch (MalformedURLException ex) {
			ex.printStackTrace();
			rval = false;
		} catch (IOException e) {
			e.printStackTrace();
			rval = false;
		} finally {
			urlConnection.disconnect();
			try {
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return rval;
	}
	
	@SuppressWarnings({ "static-access", "unchecked" })
	public void installNewKernel() {
		this.osVersion = this.checkROMType();
		
		AssetManager assets = parent.getAssets();
		
		HashMap<String, String> map = new HashMap<String, String>();
		//tools for splitting and merging ramdisk and kernel image
		map.put("dump_image", "");
		map.put("mkbootimg", "");
		map.put("unpackbootimg", "");
		if (osVersion == SENSE) {
			map.put("zImage", "sense/");
		} else {
			map.put("zImage", "aosp/");			
		}
		//banners
		map.put("default.1280x720.0.0.16", "banners/");
		map.put("default.1280x720.0.1.16", "banners/");
		map.put("default.1280x720.1.0.16", "banners/");
		map.put("default.1280x720.1.1.16", "banners/");
		//daemon
		map.put("hdmid", "bin/");
		//kernel modules
		if (osVersion == SENSE) {
			map.put("bcm4329.ko", "modules/sense/");
			map.put("sequans_sdio.ko", "modules/sense/");
		} else {
			map.put("bcm4329.ko", "modules/aosp/");
			map.put("sequans_sdio.ko", "modules/aosp/");			
		}
		
		Process p = null;
		
		try {
			p = Runtime.getRuntime().exec("su");
			
			DataOutputStream dos = new DataOutputStream(p.getOutputStream());
			
			dos.write("mount -o remount,rw /dev/block/mtdblock4 /system\n".getBytes());
			Thread.currentThread().sleep(1000);
			dos.flush();
			
			File file = new File("/data/hdmid");
			
			//make sure no previous hdmid directories or binaries are in the way of our environment setup
			dos.write("rm -rf /data/hdmid/\n".getBytes());
			Thread.currentThread().sleep(1000);
			dos.flush();
			
			if (!file.exists()) {
				dos.write("mkdir /data/hdmid\n".getBytes());
				Thread.currentThread().sleep(200);
				dos.flush();
			}
			
			file = new File("/data/hdmid/banners");
			if (!file.exists()) {
				dos.write("mkdir /data/hdmid/banners\n".getBytes());
				Thread.currentThread().sleep(200);
				dos.flush();
			}
			
			Iterator iter = map.keySet().iterator();
			while (iter.hasNext()) {
				String fileName = (String)iter.next();
				String dir = map.get(fileName);
				//(fileName.contains("/") ? "" : "")
				InputStream is = assets.open(dir + fileName);
				String fullPath = null;
//				if (dir.equalsIgnoreCase("bin/")) {
//					fullPath = "/system/bin/" + fileName;
//				} else if (dir.equalsIgnoreCase("modules/")) {
//					fullPath = "/system/lib/modules/" + fileName;
				if (dir.equalsIgnoreCase("banners/")) {
					fullPath = "/data/hdmid/banners/" + fileName;
				} else {
					fullPath = "/data/hdmid/" + 
						(fileName.contains("/") ? fileName.substring(fileName.lastIndexOf("/") + 1) : fileName);
				}
				file = new File(fullPath);
				if (!file.exists()) {
					System.out.println("Writing " + fullPath);
					OutputStream out = new FileOutputStream(new File(fullPath));
				    byte buf[] = new byte[1024];
				    int len;
				    while((len = is.read(buf)) > 0) {
				    	out.write(buf,0,len);
				    }
				    out.close();
				} else {
					System.out.println("File " + fullPath + " already exists - skipping!");
				}
			    is.close();
			}
			
//			for (String fileName : files) {
//				InputStream is = assets.open(fileName);
//				OutputStream out = new FileOutputStream(new File("/data/hdmid/" + 
//						(fileName.contains("/") ? fileName.substring(fileName.indexOf("/")) : fileName)));
//			    byte buf[] = new byte[1024];
//			    int len;
//			    while((len = is.read(buf)) > 0) {
//			    	out.write(buf,0,len);
//			    }
//			    out.close();
//			    is.close();
//			}
			
			dos.write("chmod 755 /data/hdmid/*\n".getBytes());
			Thread.currentThread().sleep(1000);
			dos.flush();
			
			//adjusted copy command to work with stock android /system/bin/toolbox
			//dos.write("cp /data/hdmid/bcm4329.ko /system/lib/modules/\n".getBytes());
			dos.write("cat /data/hdmid/bcm4329.ko > /system/lib/modules/bcm4329.ko\n".getBytes());
			Thread.currentThread().sleep(300);
			dos.flush();
			
			//adjusted copy command to work with stock android /system/bin/toolbox
			//dos.write("cp /data/hdmid/sequans_sdio.ko /system/lib/modules/\n".getBytes());
			dos.write("cat /data/hdmid/sequans_sdio.ko > /system/lib/modules/sequans_sdio.ko\n".getBytes());
			Thread.currentThread().sleep(300);
			dos.flush();
			
			//change permissions for modules to -rw-r--r-- to keep android system module permission structure
			dos.write("chmod 644 /system/lib/modules/*\n".getBytes());
			Thread.currentThread().sleep(1000);
			dos.flush();
			
			//adjusted copy command to work with stock android /system/bin/toolbox
			//dos.write("cp /data/hdmid/hdmid /system/bin/\n".getBytes());
			dos.write("cat /data/hdmid/hdmid > /system/bin/hdmid\n".getBytes());
			Thread.currentThread().sleep(300);
			dos.flush();
			
			dos.write("./data/hdmid/dump_image boot /data/hdmid/boot.img\n".getBytes());
			dos.flush();
			Thread.currentThread().sleep(1000);
			
			dos.write("./data/hdmid/unpackbootimg /data/hdmid/boot.img /data/hdmid/\n".getBytes());
			dos.flush();
			Thread.currentThread().sleep(1000);
			
			String longCommand = "echo /data/hdmid/mkbootimg " +
			"--kernel /data/hdmid/zImage " +
			"--ramdisk /data/hdmid/boot.img-ramdisk.gz " +
			"--cmdline \\\"$(cat /data/hdmid/boot.img-cmdline)\\\" " +
			"--base $(cat /data/hdmid/boot.img-base) " +
			"--output /data/hdmid/newboot.img >> /data/hdmid/createnewboot.sh" +
			"\n";
			dos.write(longCommand.getBytes());
			dos.flush();
			Thread.currentThread().sleep(500);
			
			dos.write("sh /data/hdmid/createnewboot.sh\n".getBytes());
			dos.flush();
			Thread.currentThread().sleep(2000);
			
			dos.write("flash_image boot /data/hdmid/newboot.img\n".getBytes());
			dos.flush();
			Thread.currentThread().sleep(5000);
			
			this.editor.putBoolean("kernel_installed", true);
			this.editor.commit();
			
			dos.write("reboot\n".getBytes());
			dos.flush();
		} catch (IOException ex) {
			ex.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
}
